import { _decorator, instantiate, ProgressBar, Label, Vec3, Tween, tween } from "cc";
import { EntityManager } from "../../Base/EntityManager";
import { EntityTypeEnum, IActor, InputTypeEnum, IVec2, toFixed } from "../../Common";
import { EntityStateEnum, EventEnum, SceneEnum } from "../../Enum";
import DataManager from "../../Global/DataManager";
import EventManager from "../../Global/EventManager";
import { rad2Angle } from "../../Utils";
import { WeaponManager } from "../Weapon/WeaponManager";
import { ActorStateMachine } from "./ActorStateMachine";
const { ccclass } = _decorator;

@ccclass("ActorManager")
export class ActorManager extends EntityManager implements IActor {
  //静态数据
  id: number;
  nickname: string;
  type: EntityTypeEnum;
  weaponType: EntityTypeEnum;
  bulletType: EntityTypeEnum;

  //动态数据
  hp: number;
  position: IVec2;
  direction: IVec2;

  private hpBar: ProgressBar;
  private label: Label;
  private weapon: WeaponManager;

  private tw: Tween<unknown>;
  private targetPos: Vec3;
  private isDead = false;

  init(data: IActor) {
    const { id, nickname, type, weaponType, bulletType } = data;
    this.id = id;
    this.nickname = nickname;
    this.type = type;
    this.weaponType = weaponType;
    this.bulletType = bulletType;

    this.hpBar = this.node.getComponentInChildren(ProgressBar);
    this.label = this.node.getComponentInChildren(Label);
    this.label.string = nickname;

    this.fsm = this.addComponent(ActorStateMachine);
    this.fsm.init(type);
    this.state = EntityStateEnum.Idle;

    const weaponPrefab = DataManager.Instance.prefabMap.get(this.weaponType);
    const weapon = instantiate(weaponPrefab);
    weapon.setParent(this.node);
    this.weapon = weapon.addComponent(WeaponManager);
    this.weapon.init(data);

    this.targetPos = undefined;
    this.node.active = false;
  }

  async tick(dt: number) {
    if (DataManager.Instance.myPlayerId !== this.id || this.isDead) {
      return;
    }

    if (this.hp <= 0) {
      EventManager.Instance.emit(EventEnum.GameEnd);
      this.isDead = true;
      return;
    }

    if (DataManager.Instance.jm.input.length()) {
      const { x, y } = DataManager.Instance.jm.input;
      EventManager.Instance.emit(EventEnum.ClientSync, {
        type: InputTypeEnum.ActorMove,
        id: this.id,
        direction: {
          x: toFixed(x),
          y: toFixed(y),
        },
        dt: toFixed(dt),
      });
    }
  }

  render(data: IActor) {
    this.renderHP(data);
    this.renderPosition(data);
    this.renderDirection(data);
  }

  renderHP(data: IActor) {
    this.hp = data.hp;
    this.hpBar.progress = data.hp / this.hpBar.totalLength;
  }

  renderPosition(data: IActor) {
    const newPos = new Vec3(data.position.x, data.position.y);
    if (!this.targetPos) {
      this.node.active = true;
      this.node.setPosition(newPos);
      this.targetPos = new Vec3(newPos);
    } else if (!this.targetPos.equals(newPos)) {
      this.tw?.stop();
      this.node.setPosition(this.targetPos);
      this.targetPos.set(newPos);
      this.state = EntityStateEnum.Run;
      this.tw = tween(this.node)
        .to(0.1, {
          position: this.targetPos,
        })
        .call(() => {
          this.state = EntityStateEnum.Idle;
        })
        .start();
    }
    // this.node.setPosition(data.position.x, data.position.y)
  }

  renderDirection(data: IActor) {
    const { x, y } = data.direction;
    if (x !== 0) {
      this.node.setScale(x > 0 ? 1 : -1, 1);
      this.label.node.setScale(x > 0 ? 1 : -1, 1);
      this.hpBar.node.setScale(x > 0 ? 1 : -1, 1);
    }
    const side = Math.sqrt(x * x + y * y);
    const angle = rad2Angle(Math.asin(y / side));
    this.weapon.node.setRotationFromEuler(0, 0, angle);

    // const { x, y } = joystick.input
    // let angle: number, sign: number
    // if (x !== 0) {
    //   angle = rad2Angle(Math.atan(y / x))
    //   sign = joystick.input.x > 0 ? 1 : -1
    // } else {
    //   angle = rad2Angle(Math.PI / 2)
    //   sign = joystick.input.y > 0 ? 1 : -1
    // }
    // this.node.setRotationFromEuler(0, 0, sign * angle)
  }
}
